/*****************************************************************************/
/* File: WinMain.cpp                                                         */
/* Author: Ozon, daytek                                                      */
/*                                                                           */
/* Description:																 */
/*	Defines entry point for application.									 */
/*****************************************************************************/

#include <windows.h>

#include "Physics.h"
#include "StateManager.h"
#include "MenuState.h"
#include "Level.h"
#include "Font.h"

#include "Common.h"
using namespace std;

CRenderer* g_pRenderer;

// Window handling function declaration
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


/*****************************************************************************/
/* Global variables declaration - common for all units and files             */
/*****************************************************************************/
float g_fTime = 0;	//dt - time from last frame till now
HDC g_hDC = NULL;	//device context of our window - grabbed when window is
					//created and released when destroyed
bool g_bTwoPlayers = false;
bool g_bQuit = false;
CStateManager* g_pStateManager = NULL;	//active state manager

GLuint CBrick::m_uiTexture = 0;
GLuint CBat::m_uiTexture = 0;


/*****************************************************************************/
/* Creates OpenGL Window													 */
/*****************************************************************************/
HWND CreateOpenGLWindow(LPCSTR szTitle, int iX, int iY, int iWidth, int iHeight)
{
	HWND        hWnd;	/* window */
	WNDCLASS    wndclass;
	LPCSTR szClassName = "ArkaNoeClass";
	static HINSTANCE hInstance = 0;

	/* only register the window class once - use hInstance as a flag. */
	if (!hInstance) 
	{
		hInstance = GetModuleHandle(NULL);
		wndclass.style         = CS_HREDRAW | CS_VREDRAW;
		wndclass.lpfnWndProc   = (WNDPROC)WndProc; //handling function
		wndclass.cbClsExtra    = 0;
		wndclass.cbWndExtra    = 0;
		wndclass.hInstance     = hInstance;
		wndclass.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
		wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
		wndclass.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
		wndclass.lpszMenuName  = _T("Menu");
		wndclass.lpszClassName = szClassName;

		// register class of main window
		if (!RegisterClass(&wndclass)) {
			MessageBox(NULL, "RegisterClass() failed: Cannot register window class.", "Error", MB_OK);
			return NULL;
		}
	}

	hWnd = CreateWindowEx(
		WS_EX_APPWINDOW,	// create on the top of other windows
		szClassName,
		szTitle,			// title
		WS_POPUP,			// without border or title bar
		iX,					// x
		iY,					// y 
		iWidth,				// width
		iHeight,			// heigth
		NULL,				// parent
		NULL,				// menu
		hInstance, 
		NULL);

	if (hWnd == NULL) {
		MessageBox(NULL, "CreateWindow() failed:  Cannot create a window.",
			"Error", MB_OK);
		return NULL;
	}

	ShowCursor(false);
	return hWnd;
}    

/*****************************************************************************/
/* WinMain function - defines entry point for application, creates windows   */
/* and graphics context.                                                     */
/*****************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;				/* message */
	HWND hWnd;				/* window */
	HDC hDC;				/* device context */
	DWORD dwTicks, dwNewTicks;

	// create main window
	hWnd = CreateOpenGLWindow("Arka Noe 3D", 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));	

	//get & create context
	hDC = GetDC(hWnd);

	// show main window
	ShowWindow (hWnd, nCmdShow) ;
	
	// create font on device context
	CFont::SetDeviceContext(hDC);

	// refresh window content
	UpdateWindow (hWnd) ;

	//initialize timer - get current time
	dwTicks = GetTickCount();

	// message loop
	msg.message = WM_NULL;  //initial null message

	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{

			g_pStateManager->getKeyPressed();

			//get time from last frame
			dwNewTicks = GetTickCount();
			g_fTime = dwNewTicks> dwTicks ? (dwNewTicks - dwTicks) / 1000.0f : 0.0f;
			if(g_fTime > 1.0) g_fTime = 1.0;

			bool bGameOver = g_pStateManager->Update(dwNewTicks);
			if (bGameOver)
				return false;
			
			g_pStateManager->Draw();

			dwTicks = dwNewTicks;

			//check if user quit game
			if (g_bQuit) 
			{
				return false;
			}
		}
	}

	return (int)msg.wParam;
}


/*****************************************************************************/
/* Message handling function. Determines the behaviour of window. Initialzes */
/* graphical envinroment, etc.                                               */
/*****************************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uiMsg)
	{
	case WM_CREATE:
		// Get a handle to the device context
		g_hDC = GetDC(hWnd);

		//create and init render device
		g_pRenderer = new CRenderer(g_hDC,GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
	
		if(g_pRenderer->Init()!=0)
		{
			//error!
			return 0;
		}

		// initialize state manager and start from the 'menu' state
		g_pStateManager = new CStateManager;
		g_pStateManager->ChangeState(CMenuState::GetInstance(g_pStateManager, g_pRenderer, g_hDC, hWnd));

		return 0;

	case WM_DESTROY:

		if (g_pRenderer)
		{
			//destroy render device
			g_pRenderer->Destroy();
		}

		ReleaseDC(hWnd, g_hDC);
		DestroyWindow(hWnd);
		// Release the device context

		PostQuitMessage(0);
		return 0;

	default:
		return DefWindowProc(hWnd, uiMsg, wParam, lParam);
	}
}
